package com.id.supaclean.utils

import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import android.os.Environment
import com.id.supaclean.MyApplication.Companion.appContext
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.FlowCollector
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import java.io.File

object GarbageManager {

    fun scan() = flow {
        val externalStorageFile = Environment.getExternalStorageDirectory()
        if (!externalStorageFile.isDirectory) return@flow
        val cache = appContext.filesDir
        if (!cache.isDirectory) return@flow
        val totalList = mutableSetOf<File>()
        if (externalStorageFile.listFiles() != null) {
            totalList.addAll(externalStorageFile.listFiles())
        }
        if (cache.listFiles() != null) {
            totalList.addAll(cache.listFiles())
        }
        totalList.forEach { file ->
            if (file.name == "Android") return@forEach
            file.scanGarbage()?.onEach {
                emit(it)
            }
        }
//        externalStorageFile.listFiles()?.forEach { file ->
//            if (file.name == "Android") return@forEach
//            file.scanGarbage()?.onEach { emit(it) }
//        }

    }.flowOn(Dispatchers.IO)

    private fun File.scanGarbage(depth: Int = 3): List<Garbage>? {
        if (!exists() || depth <= 0) return null

        if (isFile) {
            //空文件
            if (length() == 0L) return listOf(Garbage.EmptyFile(this))

            val lowercaseName = name.lowercase()

            //安装包
            if (lowercaseName.lastIndexOf(".apk") != -1 ||
                lowercaseName.lastIndexOf(".aab") != -1
            ) {
                return listOf(Garbage.Apk(this))
            }

            //缩略图
            if (lowercaseName.lastIndexOf(".thumbnails") != -1) {
                return listOf(Garbage.Thumbnail(this))
            }

            return listOf(Garbage.Cache(this))
        }

        val result = mutableListOf<Garbage>()

        if (this.isDirectory) {

//            //空文件夹
//            if (list().isNullOrEmpty()) return listOf(Garbage.EmptyFile(this))

            listFiles()?.forEach { itemFile ->
                itemFile.scanGarbage(depth - 1)?.let { result.addAll(it) }
            }

        }
        return result

    }

    fun cleanGarbage(garbageList: List<Garbage>) =
        flow {
            garbageList.onEach { deleteFile(it.file) }
        }.flowOn(Dispatchers.IO)

    private suspend fun FlowCollector<Long>.deleteFile(file: File) {
        try {
            if (!file.exists()) return
            if (file.isFile) {
                file.delete()
                emit(file.length())
                return
            }

            if (file.isDirectory) {
                file.listFiles()?.forEach {
                    deleteFile(it)
                }
                if (file.listFiles().isNullOrEmpty()) {
                    file.delete()
                    emit(file.length())
                    return
                }
            }
        } catch (e: Throwable) {
            if (e is CancellationException) throw e
        }
    }
}

sealed class Garbage(val file: File) {
    class Apk(file: File) : Garbage(file) {
        fun getIcon(): Drawable? {
            if (!file.exists()) return null
            return try {
                val apkPath = file.absolutePath
                val packageManager = appContext.packageManager
                val packageInfo =
                    packageManager.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES)
                val applicationInfo = packageInfo?.applicationInfo?.apply {
                    sourceDir = apkPath
                    publicSourceDir = apkPath
                }
                applicationInfo?.loadIcon(packageManager)
            } catch (e: Throwable) {
                null
            }
        }
    }

    class Thumbnail(file: File) : Garbage(file)

    class EmptyFile(file: File) : Garbage(file)

    class Cache(file: File) : Garbage(file)


}

data class GarbageGroup(val title: String, val garbageList: List<Garbage>)

fun List<Garbage>.group(): List<GarbageGroup> {
    val apks = mutableListOf<Garbage.Apk>()
    val thumbnails = mutableListOf<Garbage.Thumbnail>()
    val emptyFiles = mutableListOf<Garbage.EmptyFile>()
    val caches = mutableListOf<Garbage.Cache>()

    onEach {
        when (it) {
            is Garbage.Apk -> apks.add(it)
            is Garbage.Thumbnail -> thumbnails.add(it)
            is Garbage.EmptyFile -> emptyFiles.add(it)
            is Garbage.Cache -> caches.add(it)
        }
    }

    return listOf(
        GarbageGroup("Apk", apks),
        GarbageGroup("Thumbnail", thumbnails),
        GarbageGroup("Empty File", emptyFiles),
        GarbageGroup("Cache", caches)
    )
}

val Garbage.Apk.icon
    get():Drawable? {
        if (!file.exists()) return null
        return try {
            val apkPath = file.absolutePath
            val packageManager = appContext.packageManager
            val packageInfo =
                packageManager.getPackageArchiveInfo(apkPath, PackageManager.GET_ACTIVITIES)
            val applicationInfo = packageInfo?.applicationInfo?.apply {
                sourceDir = apkPath
                publicSourceDir = apkPath
            }
            applicationInfo?.loadIcon(packageManager)
        } catch (e: Throwable) {
            null
        }
    }

val Garbage.filename: String get() = file.name

sealed class WrapperGarbage {
    object Header : WrapperGarbage()
    data class Group(
        val title: String,
        val items: List<Item>,
        var isChecked: Boolean? = false,
        var isShowed: Boolean = false
    ) :
        WrapperGarbage()

    data class Item(val garbage: Garbage, var isChecked: Boolean = false) :
        WrapperGarbage()
}
